/**
 * Copyright (c) 2018-2022, NXOS Development Team
 * SPDX-License-Identifier: Apache-2.0
 * 
 * Contains: Clock for system 
 * 
 * Change Logs:
 * Date           Author            Notes
 * 2021-10-16     JasonHu           Init
 */

#include <base/clock.h>
#include <base/irq.h>
#include <base/delay_irq.h>

#define NX_LOG_NAME "Clock"
#include <base/log.h>

#define TIMER_IRQ   30

static unsigned int arch_timer_rate;

static int generic_timer_init(void)
{
	NX_CASM(
		"mov x0, #1\n"
		"msr cntp_ctl_el0, x0"
		:
		:
		: "memory");

	return 0;
}

static int generic_timer_reset(unsigned int val)
{
	NX_CASM(
		"msr cntp_tval_el0, %x[timer_val]"
		:
		: [timer_val] "r" (val)
		: "memory");

	return 0;
}

static unsigned int generic_timer_get_freq(void)
{
	unsigned int freq;

	NX_CASM(
		"mrs %0, cntfrq_el0"
		: "=r" (freq)
		:
		: "memory");

	return freq;
}

/**
 * TODO: NX_ClockGetMicrosecond
 */
NX_U64 NX_ClockGetMicrosecond(void)
{
    return 0;
}

NX_Error NX_HalClockHandler(NX_IRQ_Number irqno, void * arg)
{
    generic_timer_reset(arch_timer_rate);
    NX_ClockTickGo();
    return NX_EOK;
}

NX_INTERFACE NX_Error NX_HalInitClock(void)
{
    arch_timer_rate = generic_timer_get_freq();
	NX_LOG_D("cntp freq:0x%x", arch_timer_rate);
	arch_timer_rate /= NX_TICKS_PER_SECOND;

    generic_timer_init();
	generic_timer_reset(arch_timer_rate);

    NX_Error err = NX_IRQ_Bind(TIMER_IRQ, NX_HalClockHandler, NX_NULL, "Clock", 0);
    if (err != NX_EOK)
    {
        NX_LOG_E("IRQ bind failed! %d", err);
        return NX_ERROR;
    }
#if 1
    err = NX_IRQ_Unmask(TIMER_IRQ);
    if (err != NX_EOK)
    {
        NX_LOG_E("IRQ unmask failed! %d", err);
        return NX_ERROR;
    }
#endif
    return NX_EOK;
}
